package com.ddtech.business.practice.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ddtech.business.bank.entity.QuestionBankQuestion;
import com.ddtech.business.bank.entity.QuestionBankQuestionOption;
import com.ddtech.business.bank.service.QuestionBankQuestionOptionService;
import com.ddtech.business.bank.service.QuestionBankQuestionService;
import com.ddtech.business.common.BaseEntity;
import com.ddtech.business.constant.BusinessEnum;
import com.ddtech.business.constant.Del;
import com.ddtech.business.practice.dto.QueAndOptDto;
import com.ddtech.business.practice.dto.QueTypeDto;
import com.ddtech.business.practice.dto.UserRecordDto;
import com.ddtech.business.practice.dto.WorkbookDto;
import com.ddtech.business.practice.entity.PracticeUserAnswer;
import com.ddtech.business.practice.entity.PracticeUserQuestion;
import com.ddtech.business.practice.entity.PracticeUserQuestionOption;
import com.ddtech.business.practice.entity.PracticeUserRecord;
import com.ddtech.business.practice.service.*;
import com.ddtech.business.web.entity.CollectRecord;
import com.ddtech.business.web.service.CollectRecordService;
import com.ddtech.exception.BizPreconditions;
import com.ddtech.utils.PageUtil;
import com.ddtech.utils.SecurityUtils;
import com.ddtech.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class PracticeServiceImpl implements PracticeService {
    @Autowired
    private PracticeUserAnswerService practiceUserAnswerService;
    @Autowired
    private PracticeUserRecordService practiceUserRecordService;
    @Autowired
    private PracticeUserQuestionService practiceUserQuestionService;
    @Autowired
    private PracticeUserQuestionOptionService practiceUserQuestionOptionService;
    @Autowired
    private QuestionBankQuestionService questionBankQuestionService;
    @Autowired
    private QuestionBankQuestionOptionService questionBankQuestionOptionService;
    @Autowired
    private CollectRecordService collectRecordService;

    @Override
    public Object getUserRecord(IPage pageableRequest, String startTime, String endTime) {
        LambdaQueryWrapper<PracticeUserRecord> recordLambdaQueryWrapper = Wrappers.lambdaQuery();
        recordLambdaQueryWrapper.eq(PracticeUserRecord::getUserId, SecurityUtils.getUserId());
        recordLambdaQueryWrapper.eq(PracticeUserRecord::getIsDelete, Del.FALSE.getStatus());
        recordLambdaQueryWrapper.orderByDesc(PracticeUserRecord::getCreateTime);
        if(StringUtils.isNotBlank(startTime)){
            recordLambdaQueryWrapper.ge(PracticeUserRecord::getStartTime,startTime +" 00:00:00");
        }
        if(StringUtils.isNotBlank(endTime)){
            recordLambdaQueryWrapper.le(PracticeUserRecord::getEndTime,endTime +" 23:59:59");
        }
        IPage page = practiceUserRecordService.page(pageableRequest,recordLambdaQueryWrapper);
        return PageUtil.toPage(page.getRecords(), page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object workbook(WorkbookDto workbookDto) {
        PracticeUserRecord practiceUserRecord = new PracticeUserRecord();
        if (StringUtils.isBlank(workbookDto.getPracticeId())) {
            practiceUserRecord.setPracticeName( workbookDto.getCheckType()+" ("+SecurityUtils.getName() +") -" + LocalDate.now());
            practiceUserRecord.setUserId(SecurityUtils.getUserId());
            practiceUserRecord.setUserName(SecurityUtils.getName());
            practiceUserRecord.setType(workbookDto.getCheckType());
            practiceUserRecord.setIsFinish(0);
            practiceUserRecord.setStartTime(LocalDateTime.now());
            if(workbookDto.getCheckType().equals("专项检测")){
                practiceUserRecord.setBankId(workbookDto.getBankId().get(0));
            }else{
                practiceUserRecord.setBankId("all");
            }
            practiceUserRecord.init();
            practiceUserRecordService.saveOrUpdate(practiceUserRecord);
            generateQueAndOpt(workbookDto, practiceUserRecord.getId(), SecurityUtils.getUserId());
        } else {
            practiceUserRecord = practiceUserRecordService.getById(workbookDto.getPracticeId());
        }
        QueTypeDto queTypeRes = getQueList(practiceUserRecord.getId());
        queTypeRes.setPracticeId(practiceUserRecord.getId());
        queTypeRes.setCheckUserRecord(practiceUserRecord);
        return queTypeRes;
    }
    public QueTypeDto getQueList(String practiceId) {
        QueTypeDto queTypeDto = new QueTypeDto();
        String userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<PracticeUserQuestion> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(PracticeUserQuestion::getPracticeId, practiceId);
        queryWrapper.eq(PracticeUserQuestion::getUserId, userId);
        queryWrapper.orderByAsc(PracticeUserQuestion::getQuestionNum);
        List<PracticeUserQuestion> queList = practiceUserQuestionService.list(queryWrapper);
        List<PracticeUserQuestion> singleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(0)).collect(Collectors.toList());
        queTypeDto.setSingleList(getTypeQuestion(userId, singleQuestionList));
        List<PracticeUserQuestion> multipleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(1)).collect(Collectors.toList());
        queTypeDto.setMultipleList(getTypeQuestion(userId, multipleQuestionList));
        List<PracticeUserQuestion> judgeQuestionList = queList.stream().filter(item -> item.getOptionType().equals(2)).collect(Collectors.toList());
        queTypeDto.setJudgeList(getTypeQuestion(userId, judgeQuestionList));
        return queTypeDto;
    }

    public List<QueAndOptDto> getTypeQuestion(String userId, List<PracticeUserQuestion> questionList) {
        List<QueAndOptDto> resultList = new ArrayList<>();
        for (PracticeUserQuestion entity : questionList) {
            QueAndOptDto bankQueAndOpt = new QueAndOptDto(entity);
            LambdaQueryWrapper<PracticeUserQuestionOption> checkUserQuestionOptionQueryWrapper = new LambdaQueryWrapper<>();
            checkUserQuestionOptionQueryWrapper.eq(PracticeUserQuestionOption::getQuestionId, entity.getId());
            checkUserQuestionOptionQueryWrapper.eq(PracticeUserQuestionOption::getUserId, userId);
            checkUserQuestionOptionQueryWrapper.eq(PracticeUserQuestionOption::getIsDelete, Del.FALSE.getStatus());
            List<PracticeUserQuestionOption> optList = practiceUserQuestionOptionService.list(checkUserQuestionOptionQueryWrapper);
            bankQueAndOpt.setOptList(optList);
            LambdaQueryWrapper<PracticeUserAnswer> practiceUserAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
            practiceUserAnswerLambdaQueryWrapper.eq(PracticeUserAnswer::getQuestionId, entity.getId());
            practiceUserAnswerLambdaQueryWrapper.eq(PracticeUserAnswer::getIsDelete, Del.FALSE.getStatus());
            PracticeUserAnswer answer = practiceUserAnswerService.getOne(practiceUserAnswerLambdaQueryWrapper);
            if (answer != null) {
                bankQueAndOpt.setIsRight(answer.getIsRight());
                if (answer.getOptionId() != null) {
                    bankQueAndOpt.setChecked(answer.getOptionId());
                    bankQueAndOpt.setCheckedList(Arrays.asList(answer.getOptionId().split(",")));
                }
            }
            CollectRecord collectRecord = collectRecordService.getByBusId(entity.getId());
            if (collectRecord != null) {
                bankQueAndOpt.setCollect(true);
            }
            resultList.add(bankQueAndOpt);
        }
        return resultList;
    }

    @Override
    public Object getStatistics() {
        Map<String, Object> resultMap = practiceUserRecordService.getStatistics(SecurityUtils.getUserId());
        return resultMap;
    }

    public void generateQueAndOpt(WorkbookDto workbookDto, String recordId, String userId) {
        QueryWrapper<QuestionBankQuestion> questionBankQuestionQueryWrapper = questionBankQuestionService.newValidQueryWrapper();
        if (CollUtil.isNotEmpty(workbookDto.getBankId())) {
            questionBankQuestionQueryWrapper.in(QuestionBankQuestion.BANK_ID, workbookDto.getBankId());
        }
        if(workbookDto.getCheckType().equals("专项检测")){
            questionBankQuestionQueryWrapper.eq(QuestionBankQuestion.KEY_WORDS,workbookDto.getKeyWords());
        }
        questionBankQuestionQueryWrapper.eq(BaseEntity.IS_DELETE, Del.FALSE.getStatus());
        questionBankQuestionQueryWrapper.orderByAsc("RAND()");
        IPage pageableRequest = new Page( 1, 20);
//        Integer singleNum = workbookDto.getSingleNum() != null ? workbookDto.getSingleNum() : 10;
//        Integer multipleNum = workbookDto.getMultipleNum() != null ? workbookDto.getMultipleNum() : 5;
//        Integer judgeNum = workbookDto.getJudgeNum() != null ? workbookDto.getJudgeNum() : 5;

        IPage page = questionBankQuestionService.page(pageableRequest,questionBankQuestionQueryWrapper);
        //List<QuestionBankQuestion> queList = questionBankQuestionService.list(questionBankQuestionQueryWrapper);
        List<QuestionBankQuestion> queList = page.getRecords();
        //单选
        List<QuestionBankQuestion> singleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(0)).collect(Collectors.toList());
        addTypesOfProblems(recordId, userId, singleQuestionList, singleQuestionList.size());
        //多选
        List<QuestionBankQuestion> multipleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(1)).collect(Collectors.toList());
        addTypesOfProblems(recordId, userId, multipleQuestionList, multipleQuestionList.size());
        //判断
        List<QuestionBankQuestion> judgeQuestionList = queList.stream().filter(item -> item.getOptionType().equals(2)).collect(Collectors.toList());
        addTypesOfProblems(recordId, userId, judgeQuestionList, judgeQuestionList.size());
//        //单选
//        List<QuestionBankQuestion> singleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(0)).collect(Collectors.toList());
//        Integer havenSingleNum = singleNum >= singleQuestionList.size() ? singleQuestionList.size() : singleNum;
//        addTypesOfProblems(recordId, userId, singleQuestionList, havenSingleNum);
//        //多选
//        List<QuestionBankQuestion> multipleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(1)).collect(Collectors.toList());
//        Integer havenMultipleNum = multipleNum >= multipleQuestionList.size() ? multipleQuestionList.size() : multipleNum;
//        addTypesOfProblems(recordId, userId, multipleQuestionList, havenMultipleNum);
//        //判断
//        List<QuestionBankQuestion> judgeQuestionList = queList.stream().filter(item -> item.getOptionType().equals(2)).collect(Collectors.toList());
//        Integer havenJudgeNum = judgeNum >= judgeQuestionList.size() ? judgeQuestionList.size() : judgeNum;
//        addTypesOfProblems(recordId, userId, judgeQuestionList, havenJudgeNum);
    }

    private void addTypesOfProblems(String recordId, String userId, List<QuestionBankQuestion> queList, int queNum) {
        int questionNum = 1;
        for (QuestionBankQuestion questionBankQuestion : queList) {
            if (queNum > 0) {
                String id = questionBankQuestion.getId();
                String newQueId = IdWorker.getIdStr();
                PracticeUserQuestion question = new PracticeUserQuestion(questionBankQuestion);
                question.setId(newQueId);
                question.setUserId(userId);
                question.setPracticeId(recordId);
                question.setAnswerKey(questionBankQuestion.getBasis());
                question.baseInsert();
                question.setQuestionNum(questionNum++);
                practiceUserQuestionService.saveOrUpdate(question);
                //选项
                QueryWrapper<QuestionBankQuestionOption> questionBankQuestionOptionQueryWrapper = new QueryWrapper<>();
                questionBankQuestionOptionQueryWrapper.eq(QuestionBankQuestionOption.QUESTION_ID, id);
                List<QuestionBankQuestionOption> queOptList = questionBankQuestionOptionService.list(questionBankQuestionOptionQueryWrapper);
                for (QuestionBankQuestionOption questionBankQuestionOption : queOptList) {
                    PracticeUserQuestionOption questionOption = new PracticeUserQuestionOption(questionBankQuestionOption);
                    questionOption.init();
                    questionOption.setUserId(userId);
                    questionOption.setQuestionId(newQueId);
                    questionOption.setPracticeId(recordId);
                    practiceUserQuestionOptionService.saveOrUpdate(questionOption);
                }
                queNum--;
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public PracticeUserRecord commit(UserRecordDto record) {
        PracticeUserRecord checkUserRecord = practiceUserRecordService.getById(record.getPracticeId());
        BizPreconditions.check(checkUserRecord.getIsFinish() != null && checkUserRecord.getIsFinish() == 1, BusinessEnum.CHECK_COMMIT.getMsg());
        //设置用时
        LocalDateTime addTime = checkUserRecord.getStartTime();
        LocalDateTime now = LocalDateTime.now();
        //计算开始与结束的时间差
        Duration between = Duration.between(addTime, now);
        long seconds = between.getSeconds();
        checkUserRecord.setUseTime(seconds);
        checkUserRecord.setEndTime(LocalDateTime.now());
        List<PracticeUserQuestion> questionList = record.getQueList();
        //判断是否选择正确答案
        int rightCount = 0;
        int wrongCount = 0;
        double checkScore = 0.0;
        //用户答案
        List<PracticeUserAnswer> userAnswerList = record.getUserAnswerList();
        for (PracticeUserQuestion practiceUserQuestion : questionList) {
            for (PracticeUserAnswer practiceUserAnswer : userAnswerList) {
                practiceUserAnswer.init();
                if (practiceUserQuestion.getId().equals(practiceUserAnswer.getQuestionId())) {
                    practiceUserAnswer.setBankQuestionId(practiceUserQuestion.getBankQuestionId());
                    //获取正确答案
                    List<PracticeUserQuestionOption> rightList = getRightOption(practiceUserQuestion.getId());
                    // 单选
                    if (practiceUserQuestion.getOptionType() == 0 || practiceUserQuestion.getOptionType() == 2) {
                        String right = rightList.get(0).getId();
                        if (practiceUserAnswer.getOptionId() != null && practiceUserAnswer.getOptionId().equals(right)) {
                            rightCount++;
                            checkScore = checkScore + practiceUserQuestion.getScore();
                            practiceUserAnswer.setIsRight(1);
                            practiceUserAnswerService.saveOrUpdate(practiceUserAnswer);
                        } else {
                            wrongCount++;
                            practiceUserAnswer.setIsRight(0);
                            practiceUserAnswerService.saveOrUpdate(practiceUserAnswer);
                        }
                    } else {
                        //多选
                        String optIds = practiceUserAnswer.getOptionId();
                        List<String> ids = new ArrayList<>();
                        if (optIds != null && optIds.contains(",")) {
                            ids = Arrays.asList(optIds.split(","));
                        }
                        List<String> rightOpts = new ArrayList<>();
                        for (PracticeUserQuestionOption examQuestionOption : rightList) {
                            rightOpts.add(examQuestionOption.getId());
                        }
                        //对比选项是否全对
                        if (ids.containsAll(rightOpts) && rightOpts.containsAll(ids)) {
                            rightCount++;
                            checkScore = checkScore + practiceUserQuestion.getScore();
                            practiceUserAnswer.setIsRight(1);
                            practiceUserAnswerService.saveOrUpdate(practiceUserAnswer);
                        } else {
                            wrongCount++;
                            practiceUserAnswer.setIsRight(0);
                            practiceUserAnswerService.saveOrUpdate(practiceUserAnswer);
                        }
                    }
                }
            }
        }
        checkUserRecord.setRightCount(rightCount);
        checkUserRecord.setWrongCount(wrongCount);
        checkUserRecord.setSource(checkScore);
        checkUserRecord.setIsFinish(1);
        checkUserRecord.setDeptId(SecurityUtils.getDeptId());
        practiceUserRecordService.saveOrUpdate(checkUserRecord);
        return checkUserRecord;
    }

    private List<PracticeUserQuestionOption> getRightOption(String queId) {
        LambdaQueryWrapper<PracticeUserQuestionOption> examQuestionOptionQueryWrapper = Wrappers.lambdaQuery();
        examQuestionOptionQueryWrapper.eq(PracticeUserQuestionOption::getQuestionId, queId);
        examQuestionOptionQueryWrapper.eq(PracticeUserQuestionOption::getIsTrue, 1);
        return practiceUserQuestionOptionService.list(examQuestionOptionQueryWrapper);
    }

}
